package org.kanstantin.nwscan.crawler;

import jcifs.smb.NtlmAuthenticator;
import jcifs.smb.NtlmPasswordAuthentication;
import jcifs.smb.SmbException;
import jcifs.smb.SmbFile;

import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.logging.Logger;
import java.util.regex.Pattern;

/**
 * Created with IntelliJ IDEA.
 * User: const
 * Date: 12/5/12
 * Time: 8:07 PM
 * To change this template use File | Settings | File Templates.
 */
public class SambaScannerWorker extends Thread {
	private String hostname;
	private SmbFile share;
	private NtlmPasswordAuthentication NtlmAuth;
	private ResultsContainer resultContainer;
	private final static Logger Log = Logger.getLogger(SambaScannerWorker.class.getName());

	SambaScannerWorker(String hostname) {
		this.hostname = hostname;
	}

	public void run() {
		int sharesCount = processShares();
//            dumpResults();
//            Log.info(hostname + ": " + sharesCount + " shares, " + resultList.size() + " files.");
	}
/*
        private void dumpResults() {
	        resultsWriter.save(resultList);

            File f = new File(outputDir.getAbsolutePath() + File.separatorChar + hostname + ".csv");
            OutputStream fs = null;
            try {
                f.createNewFile();
                fs = new FileOutputStream(f);
            }
            catch (IOException ioex) {
                throw new RuntimeException(ioex);
            }

            PrintWriter out = new PrintWriter(fs);

            for (String s : FileList) {
                out.println(s);
            }
        }
*/

	private int processShares() {
		InetAddress inetAddress = null;
		try {
			inetAddress = InetAddress.getByName(this.hostname);
		}
		catch (UnknownHostException ex) {
			Log.severe("Unknown host: " + this.hostname);
			return 0;
		}

		String url = new String("smb://" + inetAddress.getHostAddress() + "/");

		SmbFile SmbHost = null;

		try {
			SmbHost = new SmbFile(url, NtlmAuth);
		} catch (MalformedURLException ex) {
			Log.warning("Invalid/malformed URL encountered: [" + url + "]");
			return 0;
		}

		SmbFile[] Shares = {};
		try {
			Shares = SmbHost.listFiles();
		} catch (SmbException ex) {
			Log.warning("Failed to obtain list of shares for " + this.hostname);
		}

		for (SmbFile s : Shares) {
			share = s;
			traverse(share);
		}

		return Shares.length;
	}

	private void traverse(SmbFile Node) {

		SmbFile[] Files = null;
		try {
			if (Node.isDirectory() && (!isHidden(Node))) {
				Files = Node.listFiles();
			} else {
				Log.finest("Resource is not a directory or is hidden: " + Node.getCanonicalPath());
				return;
			}
		} catch (SmbException ex) {
			Log.warning(ex.getMessage() + " - failed to obtain subtree for " + Node.getCanonicalPath());
		}

		if (Files != null) {
			for (SmbFile f : Files) {
				try {
					if (f.isFile()) {
						SearchResult result = new SearchResult();
						result.setHost(hostname);
						result.setShare(share.getShare());
						result.setPath(f.getPath().replaceAll("(smb:\\/\\/[\\d+\\.?]+)(.+)", "smb://" + hostname + "$2"));

						result.setFilename(f.getName());
						result.setExtension(parseExtension(f.getName()));
						result.setSize(f.getContentLength());
						result.setCreated(new Date(f.createTime()));
						resultContainer.addResult(result);
//	                        resultList.add(result);
//                            FileList.add(f.getCanonicalPath() + "|" + f.getContentLength() + "|" + f.getDate());
					}
					if (f.isDirectory()) {
						traverse(f);
					}
				} catch (SmbException ex) {
					Log.warning("Failed to process smb file " + f.getCanonicalPath());
				}
			}
		}
	}

	protected boolean isHidden(SmbFile file) throws SmbException {

		if (file.isHidden()) {
			return true;
		}

		return Pattern.matches("\\$/?$", file.getName());

	}

	private String parseExtension(String str) {
		if (str.contains(".")) {
			String arr[] = str.split("\\.");
			return arr[arr.length-1];
		}

		return null;
	}

	public void setNtlmAuth(NtlmPasswordAuthentication ntlmAuth) {
		NtlmAuth = ntlmAuth;
	}

	public void setResultContainer(ResultsContainer resultContainer) {
		this.resultContainer = resultContainer;
	}
}


